﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;

namespace MP3Ganizer.Common.Command
{
  /// <summary>
  /// A command whose sole purpose is to relay its functionality to other
  /// objects by invoking delegates. The default return value for the CanExecute
  /// method is 'true'.
  /// </summary>
  public class RelayCommand<T> : ICommand
  {
    #region private fields
      protected readonly Action<T> _execute;
      protected readonly Predicate<T> _canExecute;
      protected readonly object _parameter;
    #endregion

    /// <summary>
    /// Evènement levé lorsque le CanExecute a changé.
    /// </summary>
    public event EventHandler CanExecuteChanged
    {
      add
      {
        if (this._canExecute != null)
          CommandManager.RequerySuggested += value;
      }
      remove
      {
        if (this._canExecute != null)
          CommandManager.RequerySuggested -= value;
      }
    }

    protected RelayCommand()
    {

    }

    /// <summary>
    /// Initializes a new instance of the RelayCommand class
    /// </summary>
    /// <param name="execute">The execution logic.</param>
    public RelayCommand(Action<T> execute)
      : this(execute, null)
    {
    }

    /// <summary>
    /// Initializes a new instance of the RelayCommand class
    /// </summary>
    /// <param name="execute">The execution logic.</param>
    /// <param name="canExecute">The execution status logic.</param>
    public RelayCommand(Action<T> execute, Predicate<T> canExecute)
      : this(execute, canExecute, null)
    {
    }

    /// <summary>
    /// Initializes a new instance of the RelayCommand class
    /// </summary>
    /// <param name="execute">The execution logic.</param>
    /// <param name="canExecute">The execution status logic.</param>
    /// <param name="param"></param>
    public RelayCommand(Action<T> execute, Predicate<T> canExecute, object param)
    {
      if (execute == null)
        throw new ArgumentNullException("execute");

      this._execute = execute;
      this._canExecute = canExecute;
      this._parameter = param;
    }

    /// <summary>
    /// Fonction exécutant la commande
    /// </summary>
    /// <param name="parameter"></param>
    public void Execute(object parameter)
    {
      this._execute(this._parameter != null ? (T)this._parameter : (T)parameter);
    }

    /// <summary>
    /// Fonction définissant si la commande peut-être éxécutée ou non
    /// </summary>
    /// <param name="parameter"></param>
    /// <returns></returns>
    public bool CanExecute(object parameter)
    {
      return this._canExecute == null ? true : this._canExecute((T)parameter);
    }
  }
}
